<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Payment
 * @subpackage Gateway
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id:  $
 */


/**
 * @see Zend_Payment
 */
require_once 'Zend/Payment.php';


/**
 * Class for online Ecommerce charging/payments
 * 
 *
 * @category   Zend
 * @package    Zend_Payment
 * @subpackage Gateway
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id:  $
 */
class Zend_Payment_Gateway_MoneyBookers extends Zend_Payment_Gateway_Abstract
{

	/**
     * Required options per gateways, things such as suplier, merchant account id
     * email addresess
     *
     * @var array
     */
	public $_options = array(

	'debug' => false,
	'email' => null,
	'password' => null,

	);

	/**
	 * Allowed card types
	 *
	 * @var array
	 */
	public $_allowed_card_types = array(

	'Visa',
	'MasterCard',
	'Discover',
	'Amex',
	'JCB',
	'Diners',
	'Laser',
	'Solo',
	'Maestro',
	'Carte Bleue',
	'German Direct Debit',
	'Giropay',
	'Sofortueberweisung',

	);

	const TEST_URI = 'http://www.moneybookers.com/app/test_payment.pl';
	const LIVE_URI = 'https://www.moneybookers.com/app/payment.pl';
	const PAY_URI = 'https://www.moneybookers.com/app/pay.pl';
	const QUERY_URI = 'https://www.moneybookers.com/app/query.pl';
	const ON_DEMAND = 'https://www.moneybookers.com/app/ondemand_request.pl';
	const REFUND = 'https://www.moneybookers.com/app/refund.pl';
	const EMAIL_CHECK = 'https://www.moneybookers.com/app/email_check.pl';

	/**
	 * @var array | array of fields key=>value pairs
	 */
	public $_fields = array(

	'language' => 'EN', // language for the money bookers page
	'currency' => 'USD', // currency code used for transactions

	);

	/**
	 * Http client object
	 *
	 * @var object
	 */
	private $client;

	/**
	 * Raw body content
	 *
	 * @var string
	 */
	private $_rawResponseBody;

	/**
     * Constructor.
     *
     * $options is an array of key/value pairs or an instance of Zend_Config
     * containing configuration options.
     *
     * @param  array|Zend_Config $options An array or instance of Zend_Config having configuration data
     * @throws Zend_Payment_Exception
     */
	public function __construct($options)
	{
		parent::__construct($options);

		# Load Http Client
		$this->client = new Zend_Http_Client();

		# Config options
		$this->client->setConfig(array(
		'maxredirects' => 0,
		'timeout'      => 30));

		$this->client->setUri( $this->makeUri() );

		if( is_array($options) && count($options) )
		{
			foreach ($options as $optionkey => $optionvalue)
			{
				$this->addParam($optionkey, $optionvalue);
			}
		}

		$this->client->setMethod(Zend_Http_Client::POST);

	}

	/**
     * Check for config options that are mandatory.
     *
     * @throws Zend_Payment_Gateway_Exception
     */
	public function _checkRequiredOptions()
	{

	}

	//http://www.moneybookers.com/merchant/en/moneybookers_gateway_manual.pdf

	/**
	 * Do Transfer manual API Call
	 *
	 * @param string $_emailAddress
	 * @param float $amount
	 * @param string $_detailDesc
	 * @param string $_detailText
	 * @param unknown_type $autoRedirect
	 * @return unknown
	 */
	public function doTransferManual( $_emailAddress=null, $amount, $_detailDesc, $_detailText, $autoRedirect=false )
	{
		# Make sure email exists
		if( $_emailAddress === null && !$this->_options['email'] )
		{
			throw new Zend_Payment_Gateway_Exception("option values 'email' must be specified to use this method");
		}

		# Sort email thingy
		$_usedEmailAddress = $_emailAddress ? $_emailAddress : $this->_options['email'];

		$_stack = array();
		$_stack[] = "pay_to_email={$_usedEmailAddress}";
		$_stack[] = "amount={$amount}";
		$_stack[] = "detail1_description={$_detailDesc}";
		$_stack[] = "detail1_text={$_detailText}";
		
		# Add all others
		if( is_array($this->_fields) && count($this->_fields) )
		{
			foreach($this->_fields as $fieldkey => $fieldvalue)
			{
				$_stack[] = "{$fieldkey}={$fieldvalue}";
			}
		}

		# Pass in default values
		if(!isset($params['currency']))
		{
			$_stack[] = "currency=USD";
		}

		if(!isset($params['language']))
		{
			$_stack[] = "language=EN";
		}

		# Build everything
		if( $this->_options['debug'] )
		{
			$_urlCombined = self::TEST_URI . '?' .  implode("&", $_stack);
		}
		else
		{
			$_urlCombined = self::LIVE_URI . '?' .  implode("&", $_stack);
		}

		if( $autoRedirect === true )
		{
			header("Location: ".$_urlCombined);
			return;
		}

		return $_urlCombined;
	}

	/**
	 * Set values in runtime
	 *
	 * @param array $_values
	 */
	public function setOptions( $_values=array() )
	{
		if( is_array($_values) && count($_values) )
		{
			foreach ($_values as $optionkey => $optionvalue)
			{
				$this->addParam($optionkey, $optionvalue);
			}
		}
	}

	/**
	 * Get value of a field key
	 *
	 * @param string $value
	 * @return bool|string
	 */
	public function getValue($key)
	{
		return array_key_exists($key, $this->_response) ? $this->_reponse[$key] : null;
	}

	/**
	 * Prepare API Call
	 * 
	 * 
	 * @link http://www.moneybookers.com/merchant/en/automated_payments_interface_manual.pdf
	 *
	 * @param string $email
	 * @param string $password
	 * @param float $amount
	 * @package bool $autoContinue
	 * 
	 * @return array
	 */
	public function doTransferAuto( $action, $url, $email=null, $password=null, $amount, $autoContinue=false, $autoContinueAction=null )
	{
		if( $email === null && !$this->_options['email'] || $password === null && !$this->_options['password'] )
		{
			throw new Zend_Payment_Gateway_Exception("option values 'email' and 'password' must be specified to use this method");
		}
		
		if( !$action || !$url )
		{
			throw new Zend_Payment_Gateway_Exception("action and url must be specifed");
		}

		$this->addParam('action', $action);
		$this->client->setUri( $url );

		$this->addParam('email', $email ? $email : $this->_options['email'] );
		$this->addParam('password', $password ? $password : $this->_options['password'] );
		$this->addParam('amount', $amount);
		
		$response = $this->_buildRequest();
		
		if( $autoContinue && $this->isSuccess() )
		{
			return $this->doTransferContinue( $response['sid'], $autoContinueAction );
		}

		return $this->_response;
	}
	
	/**
	 * Custom Action API Call
	 * 
	 * Perform any action avilable from the API automated manual
	 * 
	 * @link http://www.moneybookers.com/merchant/en/automated_payments_interface_manual.pdf
	 *
	 * @param string $action
	 * @return array
	 */
	public function customAction( $action )
	{
		if( !$action )
		{
			throw new Zend_Payment_Gateway_Exception("action must be specifed");
		}

		$this->client->setUri( self::QUERY_URI );
		$this->addParam('action', $action);
		
		return $this->_buildRequest();
	}
	
	/**
	 * Do Transfer API Call
	 * 
	 * @link http://www.moneybookers.com/merchant/en/automated_payments_interface_manual.pdf
	 *
	 * @param string $_SID
	 * @param string $action
	 * @return array
	 */
	public function doTransferContinue( $_SID, $action='transfer' )
	{
		$this->addParam('action', $action);
		$this->addParam('sid', $_SID);

		return $this->_buildRequest();
	}

	/**
	 * Was the last request successful
	 *
	 * @param array $params
	 * @return bool
	 */
	public function isSuccess( $params=array() )
	{
		if(is_array($params) && count($params))
		{
			return (isset($params['ok']) && $params['ok'] != '') ? true : false;
		}
		
		return (isset($this->_response['ok']) && $this->_response['ok'] != '') ? true : false;
	}

	/**
	 * Did we have an error on our last request
	 *
	 * @param bool $params
	 * @return bool
	 */
	public function isFailed( $params=array() )
	{
		if(is_array($params) && count($params))
		{
			return (isset($params['error']) && $params['error'] != '') ? true : false;
		}
		
		return (isset($this->_response['error']) && $this->_response['error'] != '') ? true : false;
	}

	/**
	 * Get the error string if exists
	 *
	 */
	public function getError()
	{
		return $this->_response['error']['error_msg'] ? $this->_response['error']['error_msg'] : null;
	}

	/**
	 * Toggle test mode
	 *
	 * @param bool $flag
	 */
	public function toggleTestMode($flag)
	{
		if($flag !== null)
		{
			$this->_options['debug'] = (bool) $flag;
		}
	}

	/**
	 * What kind of request to perform
	 *
	 * @param string $key
	 * @param string $value
	 * @return object
	 */
	private function addParam($key, $value)
	{
		$this->client->setParameterPost( $key , $value );
	}

	/**
	 * Determine which URL to use
	 *
	 */
	private function makeUri()
	{
		return self::PAY_URI;
	}

	/**
	 * Explode the response and build an array
	 *
	 * @return array
	 */
	private function explodeResponse()
	{
		$config = new Zend_Config_Xml($this->_response);
		$response = $config->toArray();
		
		# Make sure we clear to success
		if( !$this->isFailed($response) )
		{
			$response['ok'] = 'ok';
		}
		
		return $response;
	}


	/**
	 * Build the request and return response array
	 *
	 * @return array
	 */
	private function _buildRequest()
	{
		# Add all other values
		if( is_array($this->_fields) && count($this->_fields) )
		{
			foreach ($this->_fields as $key => $value)
			{
				$this->addParam($key, $value);
			}
		}

		# Send
		$response = $this->client->request();

		# No Response
		if(!$response)
		{
			$this->_error_string = $response->getMessage();
			$this->_errorcode = $response->getStatus();
		}

		# Get response
		$this->_response = $response->getBody();
		$this->_rawResponseBody = $response->getBody();

		# Explode the response
		$this->_response = $this->explodeResponse();

		# Empty the fields array
		$this->_fields = array();

		return $this->_response;
	}
}
